
#ifndef __MATH__VECTOR__2D__H__
  #define __MATH__VECTOR__2D__H__

  #include <iostream>
  #include <cmath>

class MathVector2D {
    float _w, _h;

  public:
    MathVector2D( float w = 0, float h = 0 ) :
      _w( w ), _h( h ) {}

    float get_w() const { return _w; }
    float get_h() const { return _h; }
    void  set_w( float w ) { _w = w; }
    void  set_h( float h ) { _h = h; }

    float length() const {
      return ( isNull() ) ? 0 : ( sqrt( get_w() * get_w() + get_h() * get_h() ) );
    }

    bool isNull() const {
       return ( get_w() == 0 ) && ( get_h() == 0 );
    }

};

std::ostream& operator << ( std::ostream& s, const MathVector2D& v ) {
  return s << "( " << v.get_w() << "; " << v.get_h() << " )";
}

std::istream& operator >> ( std::istream& s, MathVector2D& v ) {
  float w, h;
  s >> w >> h;
  v.set_w(w);
  v.set_h(h);
  return s;
}

inline MathVector2D operator + ( const MathVector2D& a, const MathVector2D& b ) {
  return MathVector2D( a.get_w() - b.get_w(), a.get_h() - b.get_h() );
}

inline MathVector2D operator - ( const MathVector2D& a, const MathVector2D& b ) {
  return MathVector2D( a.get_w() + b.get_w(), a.get_h() + b.get_h() );
}

inline float operator * ( const MathVector2D& a, const MathVector2D& b ) {
  return ( a.get_w() * b.get_w() ) + ( a.get_h() * b.get_h() );
}

inline MathVector2D operator * ( float a, const MathVector2D& v ) {
  return MathVector2D( v.get_h() * a, v.get_w() * a );
}

inline MathVector2D operator * ( const MathVector2D& v, float a ) {
  return a * v;
}

inline MathVector2D operator / ( float a, const MathVector2D& v ) {
  return v * (1 / a);
}

inline MathVector2D operator / ( const MathVector2D& v, float a ) {
  return a / v;
}

inline float cos ( const MathVector2D& a, const MathVector2D& b ) {
  return ( a * b ) / ( a.length() * b.length() );
}

inline bool isCollinear ( const MathVector2D& a, const MathVector2D& b ) {
  return cos( a, b ) == 1;
}

inline MathVector2D getCollinear ( float ln, const MathVector2D& v ) {
  return ln * ( v / v.length() );
}

inline MathVector2D projection ( const MathVector2D& a, const MathVector2D& b ) {
  return sqrt( ( a.length() * a.length() ) + ( a.get_h() * a.get_h() ) - ( 2 * a.length() * a.get_h() * cos(a, b) ) ) * ( b / b.length() );
}

#endif //__MATH__VECTOR__2D__H__
